package com.hex.ds.hdtp.core.app.metadata.service.impl;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.hex.ds.hdtp.core.app.common.entity.BasicTransferInfo;
import com.hex.ds.hdtp.core.app.common.page.PageData;
import com.hex.ds.hdtp.core.app.common.page.converter.IPageAndPageDtoConverter;
import com.hex.ds.hdtp.core.app.common.page.dto.PageDto;
import com.hex.ds.hdtp.core.app.common.util.ExcelDownUtil;
import com.hex.ds.hdtp.core.app.common.util.SourceMethodUtil;
import com.hex.ds.hdtp.core.app.data.configuration.dto.requestDto.TableConvertRequestDto;
import com.hex.ds.hdtp.core.app.data.configuration.dto.response.TableConvertResponseDto;
import com.hex.ds.hdtp.core.app.data.configuration.service.Impl.TableConvertService;
import com.hex.ds.hdtp.core.app.data.table.converter.ITableTransferFieldMapConverter;
import com.hex.ds.hdtp.core.app.data.table.dto.request.TableTransferFieldMapRequestDto;
import com.hex.ds.hdtp.core.app.data.table.dto.response.TableTransferFieldMapResponseDto;
import com.hex.ds.hdtp.core.app.metadata.dto.request.SourceInfoExcelDto;
import com.hex.ds.hdtp.core.app.metadata.service.ISourceConfInfoService;
import com.hex.ds.hdtp.core.app.metadata.service.ISourceConfTemplateService;
import com.hex.ds.hdtp.core.app.metadata.service.ISourceInfoService;
import com.hex.ds.hdtp.core.inf.common.constant.CoreConst;
import com.hex.ds.hdtp.core.inf.common.exception.SourceSystemException;
import com.hex.ds.hdtp.core.inf.common.page.Page;
import com.hex.ds.hdtp.core.inf.metadata.entity.TableFieldsEntity;
import com.hex.ds.hdtp.core.inf.metadata.po.SourceConfInfoPo;
import com.hex.ds.hdtp.core.inf.metadata.po.SourceConfTemplatePo;
import com.hex.ds.hdtp.core.inf.metadata.po.SourceInfoPo;
import com.hex.ds.hdtp.core.inf.metadata.repository.ISourceInfoRepository;
import com.hex.ds.hdtp.core.inf.metadata.service.ISourceMethodHandlerContext;
import liquibase.util.StringUtils;
import liquibase.util.file.FilenameUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.*;
import java.util.stream.Collectors;

import static com.hex.bigdata.hbda.utils.FileUtil.upload;

/**
 * @Package: com.hex.hdc.web.cluster.services.impl
 * @ClassName DataSourceInfoService
 * @Description:
 * @Author: tj
 * @Date 2021-06-29 10:41
 * @Version v1.0
 **/
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class SourceInfoService implements ISourceInfoService {

    private final ISourceInfoRepository sourceInfoRepository;

    private final ISourceConfInfoService sourceConfInfoService;

    private final ISourceConfTemplateService sourceConfTemplateService;

    private final IPageAndPageDtoConverter pageAndPageDtoConverter;

    private final ISourceMethodHandlerContext sourceMethodHandlerContext;

    private final TableConvertService tableConvertService;

    private final ITableTransferFieldMapConverter tableTransferFieldMapConverter;

    @Value("${file.path}")
    private String filePath;

    /*
     * @Method: findListByPage <br>
     * @Param: [sourceInfoRequestDto, pageDto] <br>
     * @Return: com.hex.hdc.center.app.common.page.PageData <br>
     * @Description：分页查询数据源基本信息<br>
     * @Author： wz.li<br>
     * @Date： 2022/5/6 15:02 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public PageData queryListByPage(SourceInfoPo sourceInfoPo, PageDto pageDto) {
        final Page<SourceInfoPo> pageResult = sourceInfoRepository.queryListByPage(
                sourceInfoPo, pageAndPageDtoConverter.toPage(pageDto));
        return new PageData(pageResult.getData(), pageResult.getTotal());
    }

    /*
     * @Method: add <br>
     * @Param: [requestDto] <br>
     * @Return: void <br>
     * @Description：新增数据源配置信息<br>
     * @Author： wz.li<br>
     * @Date： 2022/5/6 15:02 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    @Transactional
    public void add(SourceInfoPo sourceInfoPo) {
        // 新增数据源基本信息
        addSourceInfo(sourceInfoPo);
        // 新增数据源连接配置信息
        batchAddConfInfo(sourceInfoPo);
    }

    /**
     * @Method: add <br>
     * @Param: [sourceInfo] <br>
     * @Return: com.hex.hdc.center.app.common.dto.ResponseDto <br>
     * @Description：新增数据源基本信息 <br>
     * @Author： lwz <br>
     * @Date： 2021/8/22 18:45 <br>
     * @Version： V1.0<br>
     */
    private void addSourceInfo(SourceInfoPo sourceInfoPo) {
        int count = sourceInfoRepository.add(sourceInfoPo);
    }

    /**
     * @Method: batchAddConfInfo <br>
     * @Param: [requestDto] <br>
     * @Return: void <br>
     * @Description：添加数据源配置信息 <br>
     * @Author： lwz <br>
     * @Date： 2021/8/22 18:40 <br>
     * @Version： V1.0<br>
     */
    public void batchAddConfInfo(SourceInfoPo sourceInfoPo) {
        if (CollectionUtil.isNotEmpty(sourceInfoPo.getConfInfoList())) {
            sourceConfInfoService.removeBySourceCode(sourceInfoPo.getSourceCode());
            SourceMethodUtil.replacePlaceholder(sourceInfoPo.getConfInfoList());
            for (SourceConfInfoPo confInfoRequestDto : sourceInfoPo.getConfInfoList()) {
                confInfoRequestDto.setSourceCode(sourceInfoPo.getSourceCode());
                confInfoRequestDto.setSourceType(sourceInfoPo.getSourceType());
                sourceConfInfoService.add(confInfoRequestDto);
            }
        }
    }

    /**
     * @Method: update <br>
     * @Param: [requestDto] <br>
     * @Return: com.hex.hdc.center.app.common.dto.ResponseDto <br>
     * @Description：更新数据源配置信息 <br>
     * @Author： lwz <br>
     * @Date： 2021/8/22 18:46 <br>
     * @Version： V1.0<br>
     */
    @Override
    @Transactional
    public void modifyById(SourceInfoPo sourceInfoPo) {
        // 更新数据源基本信息
        modifySourceInfo(sourceInfoPo);
        // 新增数据源配置信息
        batchAddConfInfo(sourceInfoPo);
    }

    /*
     * @Method: modifySourceInfo <br>
     * @Param: [requestDto] <br>
     * @Return: void <br>
     * @Description：更新数据源基本信息<br>
     * @Author： wz.li<br>
     * @Date： 2022/5/9 19:21 <br>
     * @Version： V2.0.2<br>
     */
    private void modifySourceInfo(SourceInfoPo sourceInfoPo) {
        sourceInfoRepository.modifyById(sourceInfoPo);
    }

    /**
     * @Method: deleteByPkId <br>
     * @Param: [pkId] <br>
     * @Return: com.hex.hdc.center.app.common.dto.ResponseDto <br>
     * @Description：删除 <br>
     * @Author： lwz <br>
     * @Date： 2021/8/22 18:50 <br>
     * @Version： V1.0<br>
     */
    @Override
    @Transactional
    public void removeById(String pkId) {
        SourceInfoPo sourceInfo = sourceInfoRepository.queryById(pkId);
        sourceConfInfoService.removeBySourceCode(sourceInfo.getSourceCode());
        sourceInfoRepository.removeById(pkId);
    }

    /*
     * @Method: queryBySourceCode <br>
     * @Param: [sourceCode] <br>
     * @Return: com.hex.hdc.center.app.metadata.dto.response.SourceInfoResponseDto <br>
     * @Description：获取指定数据源编码的数据源基本信息<br>
     * @Author： wz.li<br>
     * @Date： 2022/5/9 19:03 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public SourceInfoPo queryBySourceCode(String sourceCode) {
        SourceInfoPo sourceInfo = sourceInfoRepository.queryBySourceCode(sourceCode);
        List<SourceConfTemplatePo> confTemplates = getConfTemplateList(sourceInfo.getSourceType(), sourceInfo.getSourceCode());
        sourceInfo.setConfTemplateList(confTemplates);
        return sourceInfo;
    }

    /**
     * @Method findDefaultSource
     * @Param
     * @Return com.hex.ds.hdtp.core.inf.metadata.po.SourceInfoPo
     * @Description 获取默认数据源
     * @Author gj.xu
     * @Date 2023/12/21 10:03
     * @Version V2.0
     */
    @Override
    public List<SourceInfoPo> findDefaultSource() {
        return sourceInfoRepository.findDefaultSource();
    }

    /*
     * @Method: checkSourceCode <br>
     * @Param: [sourceCode] <br>
     * @Return: com.hex.hdc.center.app.metadata.dto.response.SourceInfoResponseDto <br>
     * @Description：全表检测数据源编码是否已存在<br>
     * @Author： wz.li<br>
     * @Date： 2022/8/18 17:24 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public SourceInfoPo checkSourceCode(String sourceCode) {
        return sourceInfoRepository.queryBySourceCode(sourceCode);
    }

    /*
     * @Method: queryByPkId <br>
     * @Param: [pkId] <br>
     * @Return: com.hex.hdc.center.app.metadata.dto.response.SourceInfoResponseDto <br>
     * @Description：获取指定数据源全部信息<br>
     * @Author： wz.li<br>
     * @Date： 2022/5/9 19:03 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public SourceInfoPo queryByPkId(String pkId) {
        SourceInfoPo sourceInfo = sourceInfoRepository.queryById(pkId);
        List<SourceConfTemplatePo> originalConfTemplates = sourceConfTemplateService.queryListBySourceType(sourceInfo.getSourceType());
        // 使用Hutool进行深度复制
        List<SourceConfTemplatePo> confTemplates = originalConfTemplates.stream().map(original -> {
            SourceConfTemplatePo copy = new SourceConfTemplatePo();
            cn.hutool.core.bean.BeanUtil.copyProperties(original, copy);
            return copy;
        }).collect(Collectors.toList());
        // 获取已配置信息
        List<SourceConfInfoPo> sourceConfInfos = sourceConfInfoService.queryListBySourceCode(sourceInfo.getSourceCode());
        // 信息合并
        setConfVaule(confTemplates, sourceConfInfos);
        sourceInfo.setConfTemplateList(confTemplates);
        return sourceInfo;
    }

    /*
     * @Method: removeByIds <br>
     * @Param: [pkIds] <br>
     * @Return: void <br>
     * @Description：批量删除<br>
     * @Author： wz.li<br>
     * @Date： 2023/1/10 16:15 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public void removeByIds(List<String> pkIds) {
        for (String pkId : pkIds) {
            removeById(pkId);
        }
    }

    @Override
    public void testConnectById(String pkId) {
        SourceInfoPo sourceInfoPo = queryByPkId(pkId);
        List<SourceConfInfoPo> sourceConfInfoPoList = sourceConfInfoService.queryListBySourceCode(sourceInfoPo.getSourceCode());
        sourceMethodHandlerContext.getSourceMethodService(sourceInfoPo.getSourceType()).connection(sourceConfInfoPoList);
    }

    @Override
    public void testConnect(SourceInfoPo sourceInfoPo) {
        sourceMethodHandlerContext.getSourceMethodService(sourceInfoPo.getSourceType()).connection(sourceInfoPo.getConfInfoList());
    }

    @Override
    public List<String> schemas(String pkId) {
        SourceInfoPo sourceInfoPo = queryByPkId(pkId);
        return sourceMethodHandlerContext.getSourceMethodService(sourceInfoPo.getSourceType()).schemas(sourceInfoPo.getSourceCode());
    }

    @Override
    public List<String> procedures(String pkId, String schemaName) {
        SourceInfoPo sourceInfoPo = queryByPkId(pkId);
        return sourceMethodHandlerContext.getSourceMethodService(sourceInfoPo.getSourceType()).procedures(sourceInfoPo.getSourceCode(), schemaName);
    }

    @Override
    public List<String> tables(String pkId, String schemaName) {
        SourceInfoPo sourceInfoPo = queryByPkId(pkId);
        return sourceMethodHandlerContext.getSourceMethodService(sourceInfoPo.getSourceType()).tables(sourceInfoPo.getSourceCode(), schemaName);
    }

    /*
     * @Method: refreshImpalaMetadata <br>
     * @Param: [pkId, tableName] <br>
     * @Return: void <br>
     * @Description：刷新IMPALA元数据<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/25 16:05 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public void refreshImpalaMetadata(String pkId, String tableName) {
        SourceInfoPo sourceInfoPo = queryByPkId(pkId);
        sourceMethodHandlerContext.getSourceMethodService(sourceInfoPo.getSourceType())
                .executeUpdatetSql(sourceInfoPo.getSourceCode(), StrUtil.format("refresh {};", tableName));
    }

    /**
     * @Method getFieldMaps
     * @Param transferInfo
     * @Return java.util.List<com.hex.ds.hdtp.core.app.data.table.dto.response.TableTransferFieldMapResponseDto>
     * @Description 连接表获取字段映射
     * @Author gj.xu
     * @Date 2024/2/18 15:02
     * @Version V2.0
     */
    public List<TableTransferFieldMapResponseDto> getFieldMaps(BasicTransferInfo transferInfo) {
        List<TableTransferFieldMapResponseDto> tableTransferFieldMapResponseDtos = new ArrayList<>();
        String sourcePkId = queryBySourceCode(transferInfo.getSourceCode()).getPkId();
        List<TableFieldsEntity> tableFieldsEntities = tablesStructure(sourcePkId, transferInfo.getSourceSchema(), transferInfo.getSourceTable());
        List<TableTransferFieldMapRequestDto> tableTransferFieldMapRequestDtos = tableTransferFieldMapConverter.toFieldMapRequestDtoList(tableFieldsEntities);
        String sourceType = queryBySourceCode(transferInfo.getSourceCode()).getSourceType();
        String targetType = queryBySourceCode(transferInfo.getTargetCode()).getSourceType();
        List<TableConvertResponseDto> tableConvertResponseDtos = tableConvertService.queryList(new TableConvertRequestDto().setOriginalServer(sourceType).setTargetServer(targetType));
        try {
            // ① 字段名的映射
            List<String> newFieldsName = fieldNameMapping(tableFieldsEntities, tableConvertResponseDtos);
            // ② 字段类型的映射
            List<String> newFieldsType = fieldTypeMapping(tableFieldsEntities, tableConvertResponseDtos);
            // 字段长度的映射
            List<String> newFieldsLength = fieldLengthMapping(tableFieldsEntities, tableConvertResponseDtos);
            // ③ 整合字段信息
            List<TableTransferFieldMapRequestDto> tableTransferFieldMapRequest = integrateInfo(tableTransferFieldMapRequestDtos, newFieldsName, newFieldsType, newFieldsLength);
            for (int i = 0; i < tableTransferFieldMapRequest.size(); i++) {
                TableTransferFieldMapResponseDto tableTransferFieldMapResponseDto = new TableTransferFieldMapResponseDto();
                TableTransferFieldMapRequestDto tableTransferFieldMapRequestDto = tableTransferFieldMapRequest.get(i);
                BeanUtils.copyProperties(tableTransferFieldMapRequestDto, tableTransferFieldMapResponseDto);
                tableTransferFieldMapResponseDtos.add(tableTransferFieldMapResponseDto);
            }
        } catch (Exception e) {
            throw new SourceSystemException("连接表获取字段映射失败", e);
        }
        return tableTransferFieldMapResponseDtos;
    }

    public List<String> fieldNameMapping(List<TableFieldsEntity> tableFieldsEntities, List<TableConvertResponseDto> tableConvertResponseDtos) {
        // ① 过滤出字段名称的映射并转为Map<源类型, 目标类型>的方式
        Map<String, String> fieldsMap = tableConvertResponseDtos.stream()
                .filter(map -> map.getConvertType().equals("fieldName"))
                .collect(Collectors.toMap(TableConvertResponseDto::getOriginalValue, TableConvertResponseDto::getTargetValue, (key1, key2) -> key2));
        // ② 从字段信息中提取出字段名称
        List<String> fieldsName = tableFieldsEntities.stream().map(TableFieldsEntity::getColumnName).collect(Collectors.toList());
        List<String> newFieldsName = new ArrayList<>();
        for (String fieldName : fieldsName) {
            newFieldsName.add((fieldsMap.get(fieldName) == null) ? fieldName : fieldsMap.get(fieldName));
        }
        return newFieldsName;
    }


    public List<String> fieldTypeMapping(List<TableFieldsEntity> tableFieldsEntities, List<TableConvertResponseDto> tableConvertResponseDtos) {
        // ① 过滤出字段类型的映射并转为Map<源类型, 目标类型>的方式
        Map<String, String> fieldsMap = tableConvertResponseDtos.stream()
                .filter(map -> map.getConvertType().equals("fieldType"))
                .collect(Collectors.toMap(TableConvertResponseDto::getOriginalValue, TableConvertResponseDto::getTargetValue, (key1, key2) -> key2));
        // ② 从字段信息中提取出字段类型信息
        List<String> fieldsType = tableFieldsEntities.stream().map(TableFieldsEntity::getColumnType).collect(Collectors.toList());
        List<String> newFieldsType = new ArrayList<>();
        for (String fieldType : fieldsType) {
            newFieldsType.add((fieldsMap.get(fieldType) == null) ? fieldType : fieldsMap.get(fieldType));
        }
        return newFieldsType;
    }

    public List<String> fieldLengthMapping(List<TableFieldsEntity> tableFieldsEntities, List<TableConvertResponseDto> tableConvertResponseDtos) {
        // ① 过滤出字段长度的映射并转为<字段类型=>字段类型, 系数>的方式
        Map<String, Float> fieldsMap = tableConvertResponseDtos.stream()
                .filter(map -> map.getConvertType().equals("fieldType"))
                .collect(Collectors.toMap(TableConvertResponseDto::getOriginalValue, TableConvertResponseDto::getCoefficient, (key1, key2) -> key2));
        List<String> fieldsType = tableFieldsEntities.stream().map(TableFieldsEntity::getColumnType).collect(Collectors.toList());
        List<String> fieldsLength = tableFieldsEntities.stream().map(TableFieldsEntity::getColumnLength).collect(Collectors.toList());
        List<String> newFieldsLength = new ArrayList<>();
        for (int i = 0; i < tableFieldsEntities.size(); i++) {
            //处理字符串类型 length * 系数
            if (fieldsMap.get(fieldsType.get(i)) != null && fieldsMap.get(fieldsType.get(i)) > 0) {
                String lengthString = fieldsLength.get(i).replace(",", ""); // 去除逗号
                newFieldsLength.add(String.valueOf(Math.round(Integer.parseInt(lengthString) * fieldsMap.get(fieldsType.get(i)))));
            } else if (fieldsMap.get(fieldsType.get(i)) != null && fieldsMap.get(fieldsType.get(i)) == -1) {
                newFieldsLength.add(fieldsLength.get(i));
            } else if (fieldsMap.get(fieldsType.get(i)) != null && fieldsMap.get(fieldsType.get(i)) == 0) {
                newFieldsLength.add("0");
            } else {
                newFieldsLength.add(fieldsLength.get(i));
            }
        }
        return newFieldsLength;
    }

    public List<TableTransferFieldMapRequestDto> integrateInfo(List<TableTransferFieldMapRequestDto> tableTransferFieldMapRequestDtos
            , List<String> fieldName, List<String> fieldType, List<String> fieldLength) {
        int flag = 0;
        for (TableTransferFieldMapRequestDto tableTransferFieldMapRequestDto : tableTransferFieldMapRequestDtos) {
            tableTransferFieldMapRequestDto.setTargetFieldName(fieldName.get(flag));
            tableTransferFieldMapRequestDto.setTargetFieldType(fieldType.get(flag));
            tableTransferFieldMapRequestDto.setTargetFieldLength(fieldLength.get(flag));
            flag++;
        }
        return tableTransferFieldMapRequestDtos;
    }

    @Override
    public List<TableFieldsEntity> tablesStructure(String pkId, String schemaName, String tableName) {
        SourceInfoPo sourceInfoPo = queryByPkId(pkId);
        return sourceMethodHandlerContext.getSourceMethodService(sourceInfoPo.getSourceType()).tableStructure(sourceInfoPo.getSourceCode(), schemaName, tableName);
    }

    @Override
    public List<TableFieldsEntity> tablesStructureByType(String pkId, String schemaName, String tableName, String fieldType) {
        SourceInfoPo sourceInfoPo = queryByPkId(pkId);
        return sourceMethodHandlerContext.getSourceMethodService(sourceInfoPo.getSourceType()).tableStructureByType(sourceInfoPo.getSourceCode(), schemaName, tableName, fieldType);
    }

    @Override
    public void executeUpdatetSql(String pkId, String updateSql) {
        SourceInfoPo sourceInfoPo = queryByPkId(pkId);
        sourceMethodHandlerContext.getSourceMethodService(sourceInfoPo.getSourceType()).executeUpdatetSql(sourceInfoPo.getSourceCode(), updateSql);
    }

    @Override
    public ByteArrayResource exportMetadata(List<String> pkIds) {
        String backUpPath = createSavePath();
        String templateFilePath = "static/SourceInfoTemplate.xlsx";
        List<SourceInfoExcelDto> sourceInfoExcelDtos = pkIds.stream()
                .map(this::queryByPkId)
                .map(sourceInfoPos -> {
                    SourceInfoExcelDto sourceInfoExcelDto = new SourceInfoExcelDto();
                    for (int i = 0; i < sourceInfoPos.getConfTemplateList().size(); i++) {
                        sourceInfoPos.getConfTemplateList().get(i).setPkId(null);
                    }
                    BeanUtils.copyProperties(sourceInfoPos, sourceInfoExcelDto);
                    sourceInfoExcelDto.setConfTemplateList(JSONUtil.toJsonStr(sourceInfoPos.getConfTemplateList()));
                    sourceInfoExcelDto.setPkId(null);
                    return sourceInfoExcelDto;
                })
                .collect(Collectors.toList());
        String saveFilePath = backUpPath + File.separator + "数据源模板.xlsx";
        ExcelDownUtil.generatedExcel(sourceInfoExcelDtos, templateFilePath, saveFilePath);
        byte[] bytes;
        try {
            bytes = Files.readAllBytes(new File(saveFilePath).toPath());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return new ByteArrayResource(bytes);
    }

    @Override
    public Map<String, Object> importMetadata(MultipartFile file) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            String backUpFilePath = backupUploadFile(file);
            List<SourceInfoExcelDto> sourceInfoExcelDtos = getExcelData(backUpFilePath);
            verify(sourceInfoExcelDtos);
            saveForExcel(sourceInfoExcelDtos);
            resultMap.put("status", true);
        } catch (Exception e) {
            resultMap.put("status", false);
            resultMap.put("message", e.getMessage());
        }
        return resultMap;
    }

    @Override
    public void modifyIsDefault(SourceInfoPo sourceInfoPo) {
        sourceInfoRepository.modifyIsDefault(sourceInfoPo);
    }

    /**
     * @Method: getConfTemplateList <br>
     * @Param: [sourceType, sourceCode] <br>
     * @Return: java.util.List<com.hex.hdc.center.app.source.dto.response.SourceConfTemplateResponseDto> <br>
     * @Description：获取数据源配置信息 <br>
     * @Author： lwz <br>
     * @Date： 2021/8/29 16:37 <br>
     * @Version： V1.0<br>
     */
    private List<SourceConfTemplatePo> getConfTemplateList(String sourceType, String sourceCode) {
        // 获取配置模板信息
        List<SourceConfTemplatePo> confTemplates = sourceConfTemplateService.queryListBySourceType(sourceType);
        // 获取已配置信息
        List<SourceConfInfoPo> sourceConfInfos = sourceConfInfoService.queryListBySourceCode(sourceCode);
        // 信息合并
        setConfVaule(confTemplates, sourceConfInfos);
        return confTemplates;
    }

    private void saveForExcel(List<SourceInfoExcelDto> sourceInfoExcelDtos) {
        sourceInfoExcelDtos.stream()
                .map(sourceInfoExcelDto -> {
                    SourceInfoPo sourceInfoPo = new SourceInfoPo();
                    BeanUtils.copyProperties(sourceInfoExcelDto, sourceInfoPo);
                    JSONArray jsonArray = JSONUtil.parseArray(sourceInfoExcelDto.getConfTemplateList());
                    List<SourceConfTemplatePo> sourceConfTemplatePos = JSONUtil.toList(jsonArray, SourceConfTemplatePo.class);
                    List<SourceConfInfoPo> sourceConfInfoPos = JSONUtil.toList(jsonArray, SourceConfInfoPo.class);
                    sourceConfInfoPos.forEach(confInfoPo -> confInfoPo.setPkId(UUID.randomUUID().toString().replace("-", "")));
                    sourceInfoPo.setConfTemplateList(sourceConfTemplatePos);
                    sourceInfoPo.setConfInfoList(sourceConfInfoPos);
                    sourceInfoPo.setPkId(UUID.randomUUID().toString().replace("-", ""));
                    System.out.println(sourceInfoPo);
                    return sourceInfoPo;
                })
                .forEach(this::add);
    }


    /**
     * @Method: setConfVaule <br>
     * @Param: [confTemplates, sourceConfInfos] <br>
     * @Return: void <br>
     * @Description：配置合并 <br>
     * @Author： lwz <br>
     * @Date： 2021/8/29 16:37 <br>
     * @Version： V1.0<br>
     */
    private void setConfVaule(List<SourceConfTemplatePo> confTemplates, List<SourceConfInfoPo> sourceConfInfos) {
        sourceConfInfos = sourceConfInfos.stream().filter(sourceConf -> StrUtil.isNotBlank(sourceConf.getConfValue())).collect(Collectors.toList());
        Map<String, String> confMap = sourceConfInfos.stream().collect(
                Collectors.toMap(SourceConfInfoPo::getConfName, SourceConfInfoPo::getConfValue));
        Set<String> placeholderAttributs = getPlaceholderAttribute(confTemplates);
        for (SourceConfTemplatePo templateResponseDto : confTemplates) {
            if (!placeholderAttributs.contains(templateResponseDto.getConfName()) && confMap.containsKey(templateResponseDto.getConfName())) {
                templateResponseDto.setConfValue(confMap.get(templateResponseDto.getConfName()));
            }
        }
    }

    private Set<String> getPlaceholderAttribute(List<SourceConfTemplatePo> confTemplates) {
        Set<String> placeholderAttributs = new HashSet<>();
        for (SourceConfTemplatePo templateResponseDto : confTemplates) {
            if (CoreConst.YES.equals(templateResponseDto.getIsPlaceholderAttribute())) {
                placeholderAttributs.add(templateResponseDto.getPlaceholderConfName());
            }
        }
        return placeholderAttributs;
    }

    private String createSavePath() {
        String savePath = filePath + File.separator + "static/downExcel/SourceInfoTemplate" + File.separator + DateUtil.today() + File.separator + DateUtil.current(false);
        FileUtil.mkdir(savePath);
        return FilenameUtils.separatorsToSystem(savePath);
    }

    private String backupUploadFile(MultipartFile multipartFile) {
        String backUpPath = FilenameUtils.separatorsToSystem(filePath + File.separator + "static/uploadFile/SourceInfoTemplate" + File.separator + DateUtil.today() + File.separator + DateUtil.current(false));
        FileUtil.mkdir(backUpPath);
        String updateFilePath = FilenameUtils.separatorsToSystem(backUpPath + File.separator);
        File file = upload(multipartFile, updateFilePath);
        log.debug("上传到服务器的EXCEL文件路径: {}", file.getPath());
        return file.getPath();
    }

    private List<SourceInfoExcelDto> getExcelData(String backUpFilePath) {
        ExcelImportResult<SourceInfoExcelDto> convertAfterList = readExcel(backUpFilePath);
        return convertAfterList.getList();
    }

    private ExcelImportResult<SourceInfoExcelDto> readExcel(String backUpFilePath) {
        ImportParams importParams = new ImportParams();
        importParams.setStartRows(1);
        return ExcelImportUtil.importExcelMore(new File(backUpFilePath), SourceInfoExcelDto.class, importParams);
    }

    private void verify(List<SourceInfoExcelDto> sourceInfoExcelDtos) {
        List<String> sourceCodes = sourceInfoExcelDtos.stream()
                .map(SourceInfoExcelDto::getSourceCode)
                .collect(Collectors.toList());
        HashSet<String> sourceSet = new HashSet<>(sourceCodes);
        if (sourceSet.size() < sourceCodes.size()) {
            throw new RuntimeException("导入失败,请校验导入文件中是否有重复数据源编码");
        }
        List<String> errorSourceCodes = sourceCodes.stream()
                .filter(sourceCode -> StringUtils.isEmpty(sourceCode) || sourceInfoRepository.queryBySourceCode(sourceCode) != null)
                .collect(Collectors.toList());
        if (!errorSourceCodes.isEmpty()) {
            String errorInfo = StrUtil.format("导入失败,请校验数据源编码{}（数据源编码重复或为空）", errorSourceCodes);
            throw new RuntimeException(errorInfo);
        }
    }
}
